package com.fangdd.logtrace.http;

import com.fangdd.logtrace.BoundsLog;
import com.fangdd.logtrace.TraceId;
import com.fangdd.logtrace.TraceRootGenerator;
import com.fangdd.logtrace.TraceWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.concurrent.Callable;

/**
 * Created by sulong on 16-9-6.
 */
public class TraceIdHttpFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(TraceIdHttpFilter.class);

    public static final String TRACE_ID_HEADER_NAME = "FDD_TRACE_ID";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        final HttpServletRequest req = (HttpServletRequest) request;
        TraceId traceId = getFromHttpHeadOrCreateNew(req);
        try {
            TraceWith.run(traceId, new Callable<Object>() {
                @Override
                public Object call() throws Exception {
                    String interfaceName = "http" + req.getMethod() + ":" + req.getRequestURI();
                    long startTime = System.currentTimeMillis();
                    try {
                        BoundsLog.calleeIn(LOGGER, interfaceName);

                        chain.doFilter(req, response);

                        BoundsLog.calleeOut(LOGGER, interfaceName, true, System.currentTimeMillis() - startTime);
                    } catch (IOException ioException) {
                        BoundsLog.calleeOut(LOGGER, interfaceName, false, System.currentTimeMillis() - startTime);
                        throw ioException;
                    } catch (ServletException servletException) {
                        BoundsLog.calleeOut(LOGGER, interfaceName, true, System.currentTimeMillis() - startTime);
                        throw servletException;
                    }

                    return null;
                }
            });
        } catch (Exception e) {
            LOGGER.error("traceId: " + traceId, e);
        }
    }

    private TraceId getFromHttpHeadOrCreateNew(HttpServletRequest request) {
        String traceIdStringFromHead = request.getHeader(TRACE_ID_HEADER_NAME);
        if (traceIdStringFromHead == null || traceIdStringFromHead.length() == 0) {
            return new TraceId(TraceRootGenerator.newUUIDRoot());
        }

        return new TraceId(traceIdStringFromHead);
    }

    @Override
    public void destroy() {

    }
}
